import json
from urllib.parse import urlparse

from django.core.exceptions import ValidationError
from django.core.validators import URLValidator, validate_ipv4_address
from django.utils.translation import gettext_lazy as _
from django.utils.deconstruct import deconstructible


class HttpURLValidator(URLValidator):
    message = _('不是一个有效的网址')
    schemes = ["http", "https"]


@deconstructible()
class JSONStringValidator:
    message = _('值必须是一个有效的JSON字符串。')
    code = 'invalid'

    def __init__(self, message=None, code=None, decoder=None):
        if message is not None:
            self.message = message
        if code is not None:
            self.code = code
        self.decoder = decoder

    def __call__(self, value):
        """
        Validate that the input value is valid json string
        """
        try:
            json.loads(value, cls=self.decoder)
        except Exception:
            raise ValidationError(self.message, code=self.code, params={'value': value})


class DomainValidator(URLValidator):
    """
    域名有效性，也支持ip地址
    """
    message = _('不是一个有效的域名。')
    code = 'invalid'

    def __call__(self, value: str):
        try:
            URLValidator()(f'https://{value}')
        except ValidationError:
            raise ValidationError(self.message, code=self.code, params={'value': value})


class RootHttpURLValidator:
    message = _('不是一个有效的根网址')
    schemes = ["http", "https"]

    def __call__(self, value):
        # 首先验证是否是合法 URL 格式
        try:
            URLValidator()(value)
        except ValidationError:
            raise ValidationError(self.message)

        # 判断是否为根网址，不能有路径、query参数和锚点
        if '?' in value or '#' in value:
            raise ValidationError(self.message)

        parsed = urlparse(value)
        if parsed.path not in ('', '/') or parsed.query or parsed.fragment:
            raise ValidationError(self.message)


json_string_validator = JSONStringValidator()
http_url_validator = HttpURLValidator()
domain_validator = DomainValidator()
root_http_url_validator = RootHttpURLValidator()
